



#ifndef _3DTYPE_H
#define _3DTYPE_H

#include "StaticMatrix.h"

typedef double Float3D;

static const Float3D precision = 0.00001f;
static const Float3D PI = 3.14159f;

inline int round(Float3D v)
{
	return (int)(v + 0.5f);
}

inline bool is_zero(Float3D v)
{
	if ( v < precision && v > -precision ) return true;
	else return false;
}

inline bool is_equal(Float3D a, Float3D b)
{
	if ( is_zero(a - b) ) return true;
	if ( is_zero((a / b) - 1) || is_zero((b / a) - 1) ) return true;
	
	return false;
}

inline bool is_greater_or_equal (Float3D _left,Float3D _right)
{
	return _left > _right || is_zero(_left - _right);
}

inline bool is_smaller_or_equal (Float3D _left,Float3D _right)
{
	return _left < _right || is_zero(_left - _right);
}

struct FloatEqualer{ 
	bool operator()(Float3D _left,Float3D _right)const
	{ return is_equal(_left ,_right);} 
};


typedef StaticMatrix<Float3D,4,4,FloatEqualer> Matrix3D;

class Vector3D : public StaticMatrix<Float3D,4,1,FloatEqualer>
{
	typedef  StaticMatrix<Float3D,4,1,FloatEqualer> Base;
public:
	Vector3D(){}
	Vector3D(const Base& _matrix):Base(_matrix){}

	Float3D& operator[](unsigned int index)				{ return (*this)(index,0);}
	const Float3D& operator[](unsigned int index)const	{ return At(index,0);}

	Float3D& x() { return (*this)[0]; }
	Float3D& y() { return (*this)[1]; }
	Float3D& z() { return (*this)[2]; }
	Float3D& h() { return (*this)[3]; }

	const Float3D& x()const { return (*this)[0]; }
	const Float3D& y()const { return (*this)[1]; }
	const Float3D& z()const { return (*this)[2]; }
	const Float3D& h()const { return (*this)[3]; }
	
	Float3D Length()const;
	Vector3D Unit()const;
};

class Point3D : public StaticMatrix<Float3D,4,1,FloatEqualer> 
{
	typedef  StaticMatrix<Float3D,4,1,FloatEqualer> Base;
public:
	Point3D(){}
	Point3D(const Base& _matrix):Base(_matrix){}

	Float3D& operator[](unsigned int index)				{ return (*this)(index,0);}
	const Float3D& operator[](unsigned int index)const	{ return At(index,0);}

	Float3D& x() { return (*this)[0]; }
	Float3D& y() { return (*this)[1]; }
	Float3D& z() { return (*this)[2]; }
	Float3D& h() { return (*this)[3]; }

	const Float3D& x()const { return (*this)[0]; }
	const Float3D& y()const { return (*this)[1]; }
	const Float3D& z()const { return (*this)[2]; }
	const Float3D& h()const { return (*this)[3]; }

	Float3D Length()const;
	Point3D Normalize()const;
};
typedef StaticMatrix<Float3D,4,1,FloatEqualer> Surface3D;

struct Line3D
{
	Surface3D surface_a;
	Surface3D surface_b;
};


typedef StaticMatrix<Float3D,3,3,FloatEqualer> Matrix2D;
class Vector2D : public StaticMatrix<Float3D,3,1,FloatEqualer>
{
	typedef  StaticMatrix<Float3D,3,1,FloatEqualer> Base;
public:
	Vector2D(){}
	Vector2D(const Base& _matrix):Base(_matrix){}

	Float3D& operator[](unsigned int index)				{ return (*this)(index,0);}
	const Float3D& operator[](unsigned int index)const	{ return At(index,0);}

	Float3D& x() { return (*this)[0]; }
	Float3D& y() { return (*this)[1]; }
	Float3D& h() { return (*this)[2]; }

	const Float3D& x()const { return (*this)[0]; }
	const Float3D& y()const { return (*this)[1]; }
	const Float3D& h()const { return (*this)[2]; }

	Vector2D Unit()const;
	Float3D Length()const;
};

class Point2D : public StaticMatrix<Float3D,3,1,FloatEqualer>
{
	typedef  StaticMatrix<Float3D,3,1,FloatEqualer> Base;
public:
	Point2D(){}
	Point2D(const Base& _matrix):Base(_matrix){}

	Float3D& operator[](unsigned int index)				{ return (*this)(index,0);}
	const Float3D& operator[](unsigned int index)const	{ return At(index,0);}

	Float3D& x() { return (*this)[0]; }
	Float3D& y() { return (*this)[1]; }
	Float3D& h() { return (*this)[2]; }

	const Float3D& x()const { return (*this)[0]; }
	const Float3D& y()const { return (*this)[1]; }
	const Float3D& h()const { return (*this)[2]; }


	Point2D Normalize()const;
	Float3D Length()const;
};

typedef StaticMatrix<Float3D,3,1,FloatEqualer> Line2D;

struct Segment2D
{
	Point2D pt_a;
	Point2D pt_b;
};


Float3D KahanSum(const Float3D A[], int size);

#endif